1 : <?php
2 : /**
3 : * Container implementation.
4 : *
5 : * PHP Version 5
6 : *
7 : * @category Ding
8 : * @package Container
9 : * @subpackage Impl
10 : * @author Marcelo Gornstein <marcelog@gmail.com>
11 : * @license http://marcelog.github.com/ Apache License 2.0
12 : * @link http://marcelog.github.com/
13 : *
14 : * Copyright 2011 Marcelo Gornstein <marcelog@gmail.com>
15 : *
16 : * Licensed under the Apache License, Version 2.0 (the "License");
17 : * you may not use this file except in compliance with the License.
18 : * You may obtain a copy of the License at
19 : *
20 : * http://www.apache.org/licenses/LICENSE-2.0
21 : *
22 : * Unless required by applicable law or agreed to in writing, software
23 : * distributed under the License is distributed on an "AS IS" BASIS,
24 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 : * See the License for the specific language governing permissions and
26 : * limitations under the License.
27 : *
28 : */
29 : namespace Ding\Container\Impl;
30 :
31 : use Ding\Helpers\ErrorHandler\ErrorInfo;
32 :
33 : use Ding\Bean\IBeanDefinitionProvider;
34 : use Ding\Cache\Impl\DummyCacheImpl;
35 : use Ding\Bean\Provider\Core;
36 : use Ding\Resource\Impl\IncludePathResource;
37 : use Ding\Resource\Impl\FilesystemResource;
38 : use Ding\Resource\Impl\URLResource;
39 : use Ding\Cache\Locator\CacheLocator;
40 : use Ding\Container\IContainer;
41 : use Ding\Aspect\AspectManager;
42 : use Ding\Aspect\InterceptorDefinition;
43 : use Ding\Aspect\AspectDefinition;
44 : use Ding\Aspect\Interceptor\IDispatcher;
45 : use Ding\Aspect\Interceptor\DispatcherImpl;
46 : use Ding\Reflection\ReflectionFactory;
47 : use Ding\Bean\Lifecycle\BeanLifecycle;
48 : use Ding\Bean\Lifecycle\BeanLifecycleManager;
49 : use Ding\Bean\Factory\Exception\BeanFactoryException;
50 : use Ding\Bean\BeanConstructorArgumentDefinition;
51 : use Ding\Bean\BeanDefinition;
52 : use Ding\Bean\BeanPropertyDefinition;
53 : use Ding\MessageSource\IMessageSource;
54 :
55 : /**
56 : * Container implementation.
57 : *
58 : * PHP Version 5
59 : *
60 : * @category Ding
61 : * @package Container
62 : * @subpackage Impl
63 : * @author Marcelo Gornstein <marcelog@gmail.com>
64 : * @license http://marcelog.github.com/ Apache License 2.0
65 : * @link http://marcelog.github.com/
66 : */
67 : class ContainerImpl implements IContainer
68 : {
69 : /**
70 : * Signals to handle.
71 : * @var array
72 : */
73 : private $_signals = array(
74 : SIGQUIT, SIGHUP, SIGINT, SIGCHLD, SIGTERM, SIGUSR1, SIGUSR2
75 : );
76 : /**
77 : * Logger.
78 : * @var Logger
79 : */
80 : private $_logger;
81 :
82 : /**
83 : * Cache for isDebugEnabled()
84 : * @var boolean
85 : */
86 : private $_logDebugEnabled;
87 :
88 : /**
89 : * Dispatcher to be cloned for proxy.
90 : * @var DispatcherImpl
91 : */
92 : private $_dispatcherTemplate = null;
93 :
94 : /**
95 : * MessageSource implementation.
96 : * @var IMessageSource
97 : */
98 : private $_messageSource = false;
99 : /**
100 : * Default options.
101 : * @var array
102 : */
103 : private static $_options = array(
104 : 'bdef' => array(),
105 : 'properties' => array(),
106 : 'drivers' => array()
107 : );
108 :
109 : /**
110 : * Registered shutdown methods for beans (destroy-methods).
111 : * @var array
112 : */
113 : private $_shutdowners = array();
114 :
115 : /**
116 : * Beans already instantiated.
117 : * @var object[]
118 : */
119 : private $_beans;
120 :
121 : /**
122 : * Holds our beans cache.
123 : * @var ICache
124 : */
125 : private $_beanCache;
126 :
127 : /**
128 : * Beans already instantiated.
129 : * @var BeanDefinition[]
130 : */
131 : private $_beanDefs;
132 :
133 : /**
134 : * Beans aliases.
135 : * @var string[]
136 : */
137 : private $_beanAliases;
138 :
139 : /**
140 : * Holds our bean definitions cache.
141 : * @var ICache
142 : */
143 : private $_beanDefCache;
144 :
145 : /**
146 : * Container instance.
147 : * @var ContainerImpl
148 : */
149 : private static $_containerInstance = false;
150 :
151 : /**
152 : * The aspect manager.
153 : * @var AspectManager
154 : */
155 : private $_aspectManager = null;
156 :
157 : /**
158 : * The lifecycle manager.
159 : * @var BeanLifecycleManager
160 : */
161 : private $_lifecycleManager = null;
162 :
163 : /**
164 : * Resources multiton.
165 : * @var IResource[]
166 : */
167 : private $_resources = false;
168 :
169 : /**
170 : * The event listeners
171 : * @var string[]
172 : */
173 : private $_eventListeners = false;
174 :
175 : /**
176 : * Bean Definition providers.
177 : * @var IBeanDefinitionProvider[]
178 : */
179 : private $_beanDefinitionProviders = array();
180 :
181 : /**
182 : * The last error message is saved, just to avoid logging repeated messages.
183 : * @var string
184 : */
185 : private $_lastErrorMessage;
186 :
187 : /**
188 : * A ReflectionFactory implementation
189 : * @var IReflectionFactory
190 : */
191 : private $_reflectionFactory;
192 :
193 : /**
194 : * A Proxy factory implementation.
195 : * @var Proxy
196 : */
197 : private $_proxyFactory;
198 :
199 : /**
200 : * Properties configured when instantiating the container and by others,
201 : * like when using a PropertiesHolder.
202 : *
203 : * @var string[]
204 : */
205 : private $_properties;
206 :
207 : /**
208 : * Prevent serialization.
209 : *
210 : * @return array
211 : */
212 : public function __sleep()
213 : {
214 1 : return array('_aspectManager', '_lifecycleManager');
215 : }
216 :
217 : /**
218 : * (non-PHPdoc)
219 : * @see Ding\Bean.IBeanDefinitionProvider::getBeanDefinitionByClass()
220 : */
221 : public function getBeanDefinitionByClass($class)
222 : {
223 3 : foreach ($this->_beanDefinitionProviders as $provider) {
224 3 : $beanDefinition = $provider->getBeanDefinitionByClass($class);
225 3 : }
226 3 : }
227 : /**
228 : * Returns a bean definition.
229 : *
230 : * @param string $name Bean name.
231 : *
232 : * @return BeanDefinition
233 : * @throws BeanFactoryException
234 : */
235 : public function getBeanDefinition($name)
236 : {
237 272 : $beanName = $name . '.beandef';
238 272 : if (isset($this->_beanAliases[$name])) {
239 1 : $name = $this->_beanAliases[$name];
240 1 : }
241 272 : if (isset($this->_beanDefs[$name])) {
242 47 : return $this->_beanDefs[$name];
243 : }
244 :
245 272 : $beanDefinition = null;
246 272 : if ($this->_beanDefCache !== null) {
247 272 : $beanDefinition = $this->_beanDefCache->fetch($beanName, $result);
248 272 : }
249 272 : if ($beanDefinition) {
250 70 : $this->_beanDefs[$name] = $beanDefinition;
251 70 : return $beanDefinition;
252 : }
253 272 : foreach ($this->_beanDefinitionProviders as $provider) {
254 272 : $beanDefinition = $provider->getBeanDefinition($name);
255 272 : if ($beanDefinition) {
256 272 : $beanDefinition->setClass($this->_searchAndReplaceProperties(
257 272 : $beanDefinition->getClass()
258 272 : ));
259 272 : break;
260 : }
261 272 : }
262 272 : if (!$beanDefinition) {
263 254 : throw new BeanFactoryException('Unknown bean: ' . $name);
264 : }
265 272 : $beanDefinition = $this->_lifecycleManager->afterDefinition($beanDefinition);
266 272 : $this->_beanDefs[$beanName] = $beanDefinition;
267 272 : $this->_beanDefCache->store($beanName, $beanDefinition);
268 272 : foreach ($beanDefinition->getAliases() as $alias) {
269 17 : $this->_beanAliases[$alias] = $name;
270 272 : }
271 272 : return $beanDefinition;
272 : }
273 :
274 : /**
275 : * Will try to search and replace the properties found in the given
276 : * value.
277 : *
278 : * @param string $value
279 : *
280 : * @return string
281 : */
282 : private function _searchAndReplaceProperties($value)
283 : {
284 272 : if (is_string($value)) {
285 272 : foreach ($this->_properties as $k => $v) {
286 46 : if (strpos($value, $k) !== false) {
287 19 : if (is_string($v)) {
288 19 : $value = str_replace($k, $v, $value);
289 19 : } else {
290 12 : $value = $v;
291 : // Assigned value is not a string, so we cant use
292 : // strpos anymore on it (i.e: cant continue replacing)
293 12 : break;
294 : }
295 19 : }
296 272 : }
297 272 : }
298 272 : return $value;
299 : }
300 :
301 : /**
302 : * Takes care of transforming a scalar value for a property or constructor
303 : * argument, into a an actual value (i.e: if its a resource://, loading it
304 : * first).
305 : *
306 : * @param mixed $value The value
307 : *
308 : * @return mixed
309 : */
310 : private function _loadValue($value)
311 : {
312 272 : $value = $this->_searchAndReplaceProperties($value);
313 272 : if (is_string($value) && strpos($value, 'resource://') === 0) {
314 2 : $value = substr($value, 11);
315 2 : return $this->getResource($value);
316 : }
317 272 : return $value;
318 : }
319 :
320 : /**
321 : * This will resolve a property (or constructor arg) definition to a final
322 : * value, being a bean reference, array of other properties (or
323 : * constructor args), etc.
324 : *
325 : * @param BeanPropertyDefinition|BeanConstructorArgumentDefinition $what
326 : *
327 : * @return void
328 : */
329 : private function _getValueFromDefinition($what)
330 : {
331 272 : $value = null;
332 272 : if ($what->isBean()) {
333 272 : $value = $this->getBean($what->getValue());
334 272 : } else if ($what->isArray()) {
335 53 : $value = array();
336 53 : foreach ($what->getValue() as $k => $v) {
337 53 : $value[$k] = $this->_getValueFromDefinition($v);
338 53 : }
339 272 : } else if ($what->isCode()) {
340 24 : $value = eval($what->getValue());
341 24 : } else {
342 272 : $value = $this->_loadValue($what->getValue());
343 : }
344 272 : return $value;
345 : }
346 :
347 : /**
348 : * Resolves all values for constructor arguments definitions in a
349 : * bean definition.
350 : *
351 : * @param BeanDefinition $definition
352 : *
353 : * @return object
354 : */
355 : private function _getConstructorValuesForDefinition($definition)
356 : {
357 272 : $args = array();
358 272 : foreach ($definition->getArguments() as $argument) {
359 272 : $args[] = $this->_getValueFromDefinition($argument);
360 272 : }
361 272 : return $args;
362 : }
363 :
364 : /**
365 : * Instantiates a bean using the constructor.
366 : *
367 : * @param BeanDefinition $definition
368 : *
369 : * @return object
370 : */
371 : private function _instantiateByConstructor(BeanDefinition $definition)
372 : {
373 272 : $args = $this->_getConstructorValuesForDefinition($definition);
374 272 : $class = $definition->getClass();
375 272 : if ($definition->hasProxyClass()) {
376 24 : $class = $definition->getProxyClassName();
377 24 : }
378 272 : $rClass = $this->_reflectionFactory->getClass($class);
379 272 : if (empty($args)) {
380 272 : return $rClass->newInstanceArgs();
381 : } else {
382 272 : return $rClass->newInstanceArgs($args);
383 : }
384 : }
385 :
386 : /**
387 : * Instantiates a bean using a factory class.
388 : *
389 : * @param BeanDefinition $definition
390 : *
391 : * @return object
392 : */
393 : private function _instantiateByFactoryClass(BeanDefinition $definition)
394 : {
395 272 : $args = $this->_getConstructorValuesForDefinition($definition);
396 272 : return forward_static_call_array(
397 272 : array($definition->getClass(), $definition->getFactoryMethod()),
398 : $args
399 272 : );
400 : }
401 :
402 : /**
403 : * Instantiates a bean using a factory bean.
404 : *
405 : * @param BeanDefinition $definition
406 : *
407 : * @return object
408 : */
409 : private function _instantiateByFactoryBean(BeanDefinition $definition)
410 : {
411 67 : $args = $this->_getConstructorValuesForDefinition($definition);
412 67 : $factoryBean = $this->getBean($definition->getFactoryBean());
413 67 : $refObject = new \ReflectionObject($factoryBean);
414 67 : $factoryMethod = $refObject->getMethod($definition->getFactoryMethod());
415 67 : return $factoryMethod->invokeArgs($factoryBean, $args);
416 : }
417 :
418 : /**
419 : * Instantiates a bean.
420 : *
421 : * @param BeanDefinition $definition
422 : *
423 : * @return object
424 : */
425 : private function _instantiate(BeanDefinition $definition)
426 : {
427 272 : if ($definition->isCreatedByConstructor()) {
428 272 : return $this->_instantiateByConstructor($definition);
429 272 : } else if ($definition->isCreatedWithFactoryBean()) {
430 67 : return $this->_instantiateByFactoryBean($definition);
431 : } else {
432 272 : return $this->_instantiateByFactoryClass($definition);
433 : }
434 : }
435 :
436 : /**
437 : * Creates whatever beans this definition depends on.
438 : *
439 : * @return void
440 : */
441 : private function _createBeanDependencies(BeanDefinition $definition)
442 : {
443 272 : foreach ($definition->getDependsOn() as $depBean) {
444 6 : $this->getBean(trim($depBean));
445 272 : }
446 272 : }
447 :
448 : /**
449 : * Will inject into the given dispatcher the necessary information to
450 : * aspects will be run correctly.
451 : *
452 : * @throws BeanFactoryException
453 : * @return void
454 : */
455 : private function _applyAspect(
456 : $targetClass, AspectDefinition $aspectDefinition, IDispatcher $dispatcher
457 : ) {
458 25 : $rClass = $this->_reflectionFactory->getClass($targetClass);
459 25 : $aspect = $this->getBean($aspectDefinition->getBeanName());
460 25 : foreach ($aspectDefinition->getPointcuts() as $pointcutName) {
461 25 : $pointcut = $this->_aspectManager->getPointcut($pointcutName);
462 25 : if ($pointcut === false) {
463 1 : throw new BeanFactoryException('Could not find pointcut: ' . $pointcutName);
464 : }
465 24 : $expression = $pointcut->getExpression();
466 24 : foreach ($rClass->getMethods() as $method) {
467 24 : $methodName = $method->getName();
468 24 : if (preg_match('/' . $expression . '/', $methodName) === 0) {
469 8 : continue;
470 : }
471 : if (
472 24 : $aspectDefinition->getType() == AspectDefinition::ASPECT_METHOD
473 24 : ) {
474 21 : $dispatcher->addMethodInterceptor($methodName, $aspect, $pointcut->getMethod());
475 21 : } else {
476 5 : $dispatcher->addExceptionInterceptor($methodName, $aspect, $pointcut->getMethod());
477 : }
478 24 : }
479 24 : }
480 24 : }
481 :
482 : /**
483 : * Applies all aspects specifically defined for this bean definition.
484 : *
485 : * @param BeanDefinition $definition
486 : * @param IDispatcher $dispatcher
487 : *
488 : * @return void
489 : */
490 : private function _applySpecificAspects(BeanDefinition $definition, IDispatcher $dispatcher)
491 : {
492 272 : if ($definition->hasAspects()) {
493 17 : foreach ($definition->getAspects() as $aspect) {
494 17 : $this->_applyAspect($definition->getClass(), $aspect, $dispatcher);
495 17 : }
496 17 : }
497 272 : }
498 :
499 : /**
500 : * Looks for any global aspects that may apply to this bean and applies them.
501 : *
502 : * @param BeanDefinition $definition
503 : * @param IDispatcher $dispatcher
504 : *
505 : * @return void
506 : */
507 : private function _applyGlobalAspects(BeanDefinition $definition, IDispatcher $dispatcher)
508 : {
509 272 : $class = $definition->getClass();
510 272 : $rClass = $this->_reflectionFactory->getClass($class);
511 272 : foreach ($this->_aspectManager->getAspects() as $aspect) {
512 29 : $expression = $aspect->getExpression();
513 29 : if (preg_match('/' . $expression . '/', $class) === 0) {
514 29 : $parentClass = $rClass->getParentClass();
515 29 : while($parentClass !== false) {
516 1 : if (preg_match('/' . $expression . '/', $parentClass->getName()) > 0) {
517 1 : $this->_applyAspect($class, $aspect, $dispatcher);
518 1 : }
519 1 : $parentClass = $parentClass->getParentClass();
520 1 : }
521 29 : } else {
522 7 : $this->_applyAspect($class, $aspect, $dispatcher);
523 : }
524 272 : }
525 272 : }
526 :
527 : /**
528 : * Applies specific bean aspects and global defined aspects.
529 : *
530 : * @param BeanDefinition $definition
531 : *
532 : * @return void
533 : */
534 : private function _applyAspects(BeanDefinition $definition)
535 : {
536 272 : $class = $definition->getClass();
537 272 : $dispatcher = clone $this->_dispatcherTemplate;
538 272 : $this->_applySpecificAspects($definition, $dispatcher);
539 272 : $this->_applyGlobalAspects($definition, $dispatcher);
540 272 : if ($dispatcher->hasMethodsIntercepted()) {
541 24 : $definition->setProxyClassName(
542 24 : $this->_proxyFactory->create($class, $dispatcher)
543 24 : );
544 24 : }
545 272 : }
546 : /**
547 : * This will create a new bean, injecting all properties and applying all
548 : * aspects.
549 : *
550 : * @throws BeanFactoryException
551 : * @return object
552 : */
553 : private function _createBean(BeanDefinition $definition)
554 : {
555 272 : $this->_lifecycleManager->beforeCreate($definition);
556 272 : $this->_createBeanDependencies($definition);
557 272 : $this->_applyAspects($definition);
558 272 : $bean = $this->_instantiate($definition);
559 272 : if (!is_object($bean)) {
560 1 : throw new BeanFactoryException(
561 1 : 'Could not instantiate ' . $definition->getName()
562 1 : );
563 : }
564 272 : $this->_assemble($bean, $definition);
565 272 : $this->_setupInitAndShutdown($bean, $definition);
566 272 : $this->_lifecycleManager->afterCreate($bean, $definition);
567 272 : return $bean;
568 : }
569 :
570 : /**
571 : * Calls init method and register shutdown method.
572 : *
573 : * @param object $bean
574 : * @param BeanDefinition $definition
575 : *
576 : * @return void
577 : */
578 : private function _setupInitAndShutdown($bean, BeanDefinition $definition)
579 : {
580 272 : if ($definition->hasInitMethod()) {
581 33 : $initMethod = $definition->getInitMethod();
582 33 : $bean->$initMethod();
583 33 : }
584 272 : if ($definition->hasDestroyMethod()) {
585 32 : $destroyMethod = $definition->getDestroyMethod();
586 32 : $this->registerShutdownMethod($bean, $destroyMethod);
587 32 : }
588 272 : }
589 :
590 : /**
591 : * Tries to inject by looking up set* methods.
592 : *
593 : * @param object $bean
594 : * @param string $name
595 : * @param string $value
596 : *
597 : * @return boolean
598 : */
599 : private function _setterInject($bean, $name, $value)
600 : {
601 272 : $methodName = 'set' . ucfirst($name);
602 272 : $rClass = $this->_reflectionFactory->getClass(get_class($bean));
603 272 : if ($rClass->hasMethod($methodName)) {
604 272 : $bean->$methodName($value);
605 272 : return true;
606 : }
607 18 : return false;
608 : }
609 :
610 : /**
611 : * Tries to inject by looking up a property by name.
612 : *
613 : * @param object $bean
614 : * @param string $name
615 : * @param string $value
616 : *
617 : * @return boolean
618 : */
619 : private function _propertyInject($bean, $name, $value)
620 : {
621 18 : $rClass = $this->_reflectionFactory->getClass(get_class($bean));
622 18 : if ($rClass->hasProperty($name)) {
623 17 : $rProperty = $rClass->getProperty($name);
624 17 : if (!$rProperty->isPublic()) {
625 11 : $rProperty->setAccessible(true);
626 11 : }
627 17 : $rProperty->setValue($bean, $value);
628 17 : return true;
629 : }
630 1 : return false;
631 : }
632 : /**
633 : * Assembles a bean (setter injection)
634 : *
635 : * @param mixed $bean
636 : * @param BeanDefinition $beanDefinition
637 : *
638 : * @return void
639 : */
640 : private function _assemble($bean, BeanDefinition $beanDefinition)
641 : {
642 272 : $this->_lifecycleManager->beforeAssemble($bean, $beanDefinition);
643 272 : foreach ($beanDefinition->getProperties() as $property) {
644 272 : $propertyName = $property->getName();
645 272 : $propertyValue = $this->_getValueFromDefinition($property);
646 : if (
647 272 : $this->_setterInject($bean, $propertyName, $propertyValue)
648 18 : || $this->_propertyInject($bean, $propertyName, $propertyValue)
649 272 : ) {
650 272 : continue;
651 : }
652 1 : throw new BeanFactoryException("Dont know how to inject: $propertyName");
653 272 : }
654 272 : $this->fillAware($beanDefinition, $bean);
655 272 : $this->_lifecycleManager->afterAssemble($bean, $beanDefinition);
656 272 : }
657 : /**
658 : * Returns a bean.
659 : *
660 : * @param string $name Bean name.
661 : *
662 : * @throws BeanFactoryException
663 : * @return object
664 : */
665 : public function getBean($name)
666 : {
667 272 : $ret = false;
668 272 : $beanDefinition = $this->getBeanDefinition($name);
669 272 : $beanName = $name . '.bean';
670 272 : if ($beanDefinition->isAbstract()) {
671 1 : throw new BeanFactoryException(
672 1 : "Cant instantiate abstract bean: $name"
673 1 : );
674 : }
675 272 : if ($beanDefinition->isPrototype()) {
676 38 : $ret = $this->_createBean($beanDefinition);
677 272 : } else if ($beanDefinition->isSingleton()) {
678 272 : if (isset($this->_beans[$beanName])) {
679 171 : $ret = $this->_beans[$beanName];
680 171 : } else {
681 272 : $ret = $this->_beanCache->fetch($beanName, $result);
682 272 : if (!$ret) {
683 272 : $ret = $this->_createBean($beanDefinition);
684 272 : }
685 272 : $this->_beans[$beanName] = $ret;
686 : }
687 272 : }
688 272 : return $ret;
689 : }
690 :
691 : /**
692 : * This will return a container
693 : *
694 : * @param array $properties Container properties.
695 : *
696 : * @return ContainerImpl
697 : */
698 : public static function getInstance(array $properties = array())
699 : {
700 272 : if (self::$_containerInstance === false) {
701 : // Init cache subsystems.
702 272 : if (isset($properties['ding']['cache'])) {
703 157 : CacheLocator::configure($properties['ding']['cache']);
704 157 : }
705 272 : \Ding\Autoloader\Autoloader::setCache(CacheLocator::getAutoloaderCacheInstance());
706 272 : if (isset($properties['ding']['log4php.properties'])) {
707 272 : \Logger::configure($properties['ding']['log4php.properties']);
708 272 : }
709 272 : self::$_containerInstance = new ContainerImpl($properties['ding']['factory']);
710 268 : }
711 268 : return self::$_containerInstance;
712 : }
713 :
714 : /**
715 : * Register a shutdown (destroy-method) method for a bean.
716 : *
717 : * @param object $bean Bean to call.
718 : * @param string $method Method to call.
719 : *
720 : * @see Ding\Container.IContainer::registerShutdownMethod()
721 : *
722 : * @return void
723 : */
724 : public function registerShutdownMethod($bean, $method)
725 : {
726 32 : $this->_shutdowners[] = array($bean, $method);
727 32 : }
728 :
729 : /**
730 : * Destructor, will call all beans destroy-methods.
731 : *
732 : * @return void
733 : */
734 : public function __destruct()
735 : {
736 16 : foreach ($this->_shutdowners as $shutdownCall) {
737 16 : $bean = $shutdownCall[0];
738 16 : $method = $shutdownCall[1];
739 16 : $bean->$method();
740 16 : }
741 16 : }
742 :
743 : /**
744 : *
745 : * Enter description here ...
746 : * @param unknown_type $messageSource
747 : */
748 : public function setMessageSource(IMessageSource $messageSource)
749 : {
750 14 : $this->_messageSource = $messageSource;
751 14 : }
752 :
753 : /**
754 : * (non-PHPdoc)
755 : * @see Ding\MessageSource.IMessageSource::getMessage()
756 : */
757 : public function getMessage($bundle, $message, array $arguments, $locale = 'default')
758 : {
759 : return
760 3 : $this->_messageSource !== false
761 3 : ? $this->_messageSource->getMessage($bundle, $message, $arguments, $locale)
762 3 : : NULL;
763 : }
764 :
765 : /**
766 : * (non-PHPdoc)
767 : * @see Ding\Resource.IResourceLoader::getResource()
768 : */
769 : public function getResource($location, $context = false)
770 : {
771 : // Missing scheme?
772 8 : $scheme = strpos($location, '://');
773 8 : if ($scheme === false) {
774 1 : $location = FilesystemResource::SCHEME . $location;
775 1 : }
776 : // Already served?
777 8 : if (isset($this->_resources[$location])) {
778 1 : return $this->_resources[$location];
779 : }
780 : // See what kind of resource to return.
781 8 : if (strpos($location, FilesystemResource::SCHEME) === 0) {
782 3 : $resource = new FilesystemResource($location, $context);
783 8 : } else if (strpos($location, IncludePathResource::SCHEME) === 0) {
784 4 : $resource = new IncludePathResource($location, $context);
785 4 : } else {
786 1 : $resource = new URLResource($location, $context);
787 : }
788 8 : $this->_resources[$location] = $resource;
789 8 : return $resource;
790 : }
791 :
792 : /**
793 : * (non-PHPdoc)
794 : * @see Ding\Container.IContainer::eventDispatch()
795 : */
796 : public function eventDispatch($eventName, $data = null)
797 : {
798 14 : $eventName = 'on' . ucfirst($eventName);
799 14 : if (isset($this->_eventListeners[$eventName])) {
800 5 : foreach ($this->_eventListeners[$eventName] as $beanName) {
801 5 : $bean = $this->getBean($beanName);
802 5 : $bean->$eventName($data);
803 5 : }
804 5 : }
805 14 : }
806 :
807 : /**
808 : * (non-PHPdoc)
809 : * @see Ding\Container.IContainer::eventListen()
810 : */
811 : public function eventListen($eventName, $beanName)
812 : {
813 7 : if (!isset($this->_eventListeners[$eventName])) {
814 7 : $this->_eventListeners[$eventName] = array();
815 7 : }
816 7 : $eventName = 'on' . ucfirst($eventName);
817 7 : $this->_eventListeners[$eventName][] = $beanName;
818 7 : }
819 :
820 : /**
821 : * (non-PHPdoc)
822 : * @see Ding\Container.IContainer::registerBeanDefinitionProvider()
823 : */
824 : public function registerBeanDefinitionProvider(IBeanDefinitionProvider $provider)
825 : {
826 272 : $this->_beanDefinitionProviders[] = $provider;
827 272 : }
828 :
829 : /**
830 : * If we dont have a ReflectionFactory yet (i.e: didnt make the call to
831 : * getBean() yet), replace it with this one.
832 : *
833 : * @param string $class The name of a class.
834 : *
835 : * @return ReflectionClass
836 : */
837 : protected function getClass($class)
838 : {
839 272 : return new \ReflectionClass($class);
840 : }
841 :
842 : /**
843 : * Will look for "aware" kind of interfaces and inject whatever necessary.
844 : *
845 : * @param BeanDefinition $def The Bean Definition
846 : * @param object $bean The bean
847 : *
848 : * @return void
849 : */
850 : public function fillAware(BeanDefinition $def, $bean)
851 : {
852 272 : $class = get_class($bean);
853 272 : $rClass = $this->_reflectionFactory->getClass($class);
854 272 : if ($rClass->implementsInterface('Ding\Reflection\IReflectionFactoryAware')) {
855 272 : $bean->setReflectionFactory($this->_reflectionFactory);
856 272 : }
857 272 : if ($rClass->implementsInterface('Ding\Bean\IBeanNameAware')) {
858 1 : $bean->setBeanName($def->getName());
859 1 : }
860 272 : if ($rClass->implementsInterface('Ding\Logger\ILoggerAware')) {
861 196 : $bean->setLogger(\Logger::getLogger($class));
862 196 : }
863 272 : if ($rClass->implementsInterface('Ding\Container\IContainerAware')) {
864 272 : $bean->setContainer($this);
865 272 : }
866 272 : if ($rClass->implementsInterface('Ding\Resource\IResourceLoaderAware')) {
867 268 : $bean->setResourceLoader($this);
868 268 : }
869 272 : if ($rClass->implementsInterface('Ding\Aspect\IAspectManagerAware')) {
870 272 : $bean->setAspectManager($this->_aspectManager);
871 272 : }
872 :
873 272 : if ($rClass->implementsInterface('Ding\Bean\IBeanDefinitionProvider')) {
874 272 : $this->registerBeanDefinitionProvider($bean);
875 272 : }
876 272 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterConfigListener')) {
877 272 : $this->_lifecycleManager->addAfterConfigListener($bean);
878 272 : }
879 272 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterDefinitionListener')) {
880 268 : $this->_lifecycleManager->addAfterDefinitionListener($bean);
881 268 : }
882 272 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeCreateListener')) {
883 1 : $this->_lifecycleManager->addBeforeCreateListener($bean);
884 1 : }
885 272 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterCreateListener')) {
886 268 : $this->_lifecycleManager->addAfterCreateListener($bean);
887 268 : }
888 272 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IBeforeAssembleListener')) {
889 1 : $this->_lifecycleManager->addBeforeAssembleListener($bean);
890 1 : }
891 272 : if ($rClass->implementsInterface('Ding\Bean\Lifecycle\IAfterAssembleListener')) {
892 1 : $this->_lifecycleManager->addAfterAssembleListener($bean);
893 1 : }
894 272 : if ($rClass->implementsInterface('Ding\Aspect\IAspectProvider')) {
895 195 : $this->_aspectManager->registerAspectProvider($bean);
896 191 : }
897 272 : if ($rClass->implementsInterface('Ding\Aspect\IPointcutProvider')) {
898 191 : $this->_aspectManager->registerPointcutProvider($bean);
899 191 : }
900 272 : }
901 :
902 : /**
903 : * Called when a signal is caught.
904 : *
905 : * @param integer $signo
906 : *
907 : * @return void
908 : */
909 : public function signalHandler($signo)
910 : {
911 2 : $msg = "Caught Signal: $signo";
912 2 : $this->_logger->warn($msg);
913 2 : $this->eventDispatch('dingSignal', $signo);
914 2 : }
915 :
916 : /**
917 : * Called by php after set_error_handler()
918 : *
919 : * @param integer $type
920 : * @param string $message
921 : * @param string $file
922 : * @param integer $line
923 : *
924 : * @return true
925 : */
926 : public function errorHandler($type, $message, $file, $line)
927 : {
928 11 : $msg = "$message in $file:$line";
929 11 : if ($msg == $this->_lastErrorMessage) {
930 1 : return;
931 : }
932 11 : $this->_lastErrorMessage = $msg;
933 11 : $this->_logger->error($msg);
934 11 : $this->eventDispatch(
935 11 : 'dingError', new ErrorInfo($type, $message, $file, $line)
936 11 : );
937 11 : return true;
938 : }
939 :
940 : // @codeCoverageIgnoreStart
941 : /**
942 : * Called by the vm after register_shutdown_function()
943 : *
944 : * @return void
945 : */
946 : public function shutdownHandler()
947 : {
948 : $msg = "Shutting down";
949 : $this->eventDispatch('dingShutdown');
950 : }
951 : // @codeCoverageIgnoreEnd
952 :
953 : /**
954 : * (non-PHPdoc)
955 : * @see Ding\Container.IContainer::registerProperties()
956 : */
957 : public function registerProperties(array $properties)
958 : {
959 272 : foreach ($properties as $key => $value) {
960 46 : if (strncmp($key, 'php.', 4) === 0) {
961 2 : ini_set(substr($key, 4), $value);
962 2 : }
963 46 : $this->_properties['${' . $key . '}'] = $value;
964 272 : }
965 272 : }
966 :
967 : /**
968 : * Constructor.
969 : *
970 : * @param array $options options.
971 : *
972 : * @return void
973 : */
974 : protected function __construct(array $options)
975 : {
976 : // Setup logger.
977 272 : $this->_logger = \Logger::getLogger(get_class($this));
978 272 : $this->_logDebugEnabled = $this->_logger->isDebugEnabled();
979 272 : $soullessArray = array();
980 272 : $this->_beanAliases = $soullessArray;
981 272 : $this->_beanDefs = $soullessArray;
982 272 : $this->_beans = $soullessArray;
983 272 : $this->_shutdowners = $soullessArray;
984 272 : $this->_resources = $soullessArray;
985 272 : $this->_eventListeners = $soullessArray;
986 272 : $this->_properties = $soullessArray;
987 :
988 : // Merge options with our defaults.
989 272 : self::$_options = array_replace_recursive(self::$_options, $options);
990 272 : $this->registerProperties(self::$_options['properties']);
991 272 : $sapi = php_sapi_name();
992 272 : if ($sapi == 'cgi' || $sapi == 'cli') {
993 272 : $handler = array($this, 'signalHandler');
994 272 : foreach ($this->_signals as $signal) {
995 272 : pcntl_signal($signal, $handler);
996 272 : }
997 272 : pcntl_sigprocmask(SIG_UNBLOCK, $this->_signals);
998 272 : }
999 272 : set_error_handler(array($this, 'errorHandler'));
1000 272 : register_shutdown_function(array($this, 'shutdownHandler'));
1001 :
1002 272 : $this->_lifecycleManager = new BeanLifecycleManager;
1003 272 : $this->_dispatcherTemplate = new DispatcherImpl();
1004 272 : $this->_aspectManager = new AspectManager();
1005 272 : $this->_beanDefCache = DummyCacheImpl::getInstance();
1006 272 : $this->_beanCache = DummyCacheImpl::getInstance();
1007 272 : $this->registerBeanDefinitionProvider(new Core(self::$_options));
1008 272 : $this->_reflectionFactory = $this;
1009 272 : $this->_reflectionFactory = $this->getBean('dingReflectionFactory');
1010 272 : $this->_proxyFactory = $this->getBean('dingProxyFactory');
1011 272 : $this->_beanDefCache = $this->getBean('dingDefinitionsCache');
1012 272 : $this->_beanCache = $this->getBean('dingBeanCache');
1013 272 : $this->_lifecycleManager = $this->getBean('dingLifecycleManager');
1014 272 : $this->_aspectManager = $this->getBean('dingAspectManager');
1015 272 : $this->_dispatcherTemplate = $this->getBean('dingAspectCallDispatcher');
1016 :
1017 : // Set drivers
1018 272 : if (isset(self::$_options['bdef']['xml'])) {
1019 168 : $xmlDriver = $this->getBean('dingXmlBeanDefinitionProvider');
1020 166 : }
1021 270 : if (isset(self::$_options['bdef']['yaml'])) {
1022 37 : $yamlDriver = $this->getBean('dingYamlBeanDefinitionProvider');
1023 35 : }
1024 268 : $this->getBean('dingPropertiesDriver');
1025 268 : $this->getBean('dingMessageSourceDriver');
1026 268 : $this->getBean('dingMethodInjectionDriver');
1027 :
1028 : // All set, continue.
1029 268 : if (isset(self::$_options['bdef']['annotation'])) {
1030 107 : $this->getBean('dingAnnotationBeanDefinitionProvider');
1031 107 : $this->getBean('dingAnnotationValueDriver');
1032 107 : $this->getBean('dingAnnotationAspectDriver');
1033 107 : $this->getBean('dingAnnotationResourceDriver');
1034 107 : $this->getBean('dingAnnotationInitDestroyMethodDriver');
1035 107 : $this->getBean('dingAnnotationRequiredDriver');
1036 107 : $this->getBean('dingMvcAnnotationDriver');
1037 107 : }
1038 268 : $this->_lifecycleManager->afterConfig();
1039 268 : }
1040 : }
|